package com.ruoyi.controller;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.dto.GasDiffusionModelDto;
import com.ruoyi.dto.GasExplosionUndergroundDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * 燃气在地下空间扩散分析模型
 */
@Api(tags = "燃气在地下空间扩散分析模型")
@RequestMapping("/gasDiffusionMode")
@RestController
public class GasDiffusionModel {

    // 常数定义
    private static final double R_GAS = 518.0;        // 天然气气体常数 J/(kg·K)
    private static final double MOLAR_MASS = 16.0;    // 相对分子质量
    private static final double KAPPA = 1.29;         // 天然气等熵指数
    private static final double D0 = 0.21;           // 基础扩散系数
    private static final double EPSILON_XI = 0.66;   // ε*ξ 经验值

    // 输入参数类
    public static class InputParameters {
        public double pressure = 200000;     // 管道压力 Pa (默认200000)
        public double temperature = 285;     // 气体温度 K (默认285)
        public String leakShape = "Circle";  // 泄漏口形状 (改为英文)
        public double leakDiameter = 0.01;   // 泄漏口直径 m (默认0.01)
        public double r0 = 1.0;              // 到管线的最小距离 m (默认1.0)
        public double time;                   // 时间 s
    }

    // 计算结果类
    public static class CalculationResult {
        public double leakTime;  // 泄露时间
        public double massFlowRate;           // 泄漏质量流量 kg/s
        public double diffusionCoefficient;   // 相对扩散系数 m²/s
        public Map<Double, Double> concentrationDistribution; // 浓度分布
        public double maxConcentrationDistance; // 达到1%浓度的最大距离
    }

    // 获取泄漏孔口流量系数
    private static double getFlowCoefficient(String leakShape) {
        switch (leakShape.toLowerCase()) {
            case "circle": return 1.00;
            case "triangle": return 0.95;
            case "rectangle": return 0.90;
            default: return 1.00;
        }
    }

    // 高斯误差函数近似计算
    private static double erf(double x) {
        if (x < 0) return -erf(-x);

        double[] a = {0.254829592, -0.284496736, 1.421413741,
                -1.453152027, 1.061405429};
        double p = 0.3275911;

        double t = 1.0 / (1.0 + p * x);
        double sum = a[4];

        for (int i = 3; i >= 0; i--) {
            sum = sum * t + a[i];
        }

        return 1.0 - sum * Math.exp(-x * x);
    }

    // 计算瞬时泄漏量 qm (kg/s) - 主要公式1
    public static double calculateMassFlowRate(InputParameters params) {
        double alpha = getFlowCoefficient(params.leakShape);
        double d = params.leakDiameter;
        double P = params.pressure;
        double T = params.temperature;

        // 公式: qm = (α * π * d² / 4) * (P / √(R*T)) * √[κ * M * (2/(κ+1))^((κ+1)/(κ-1))]

        // 第一部分: α * π * d² / 4
        double areaFactor = alpha * Math.PI * d * d / 4.0;

        // 第二部分: P / √(R*T)
        double pressureFactor = P / Math.sqrt(R_GAS * T);

        // 第三部分: √[κ * M * (2/(κ+1))^((κ+1)/(κ-1))]
        double exponent = (KAPPA + 1) / (KAPPA - 1);
        double kappaFactor = Math.sqrt(KAPPA * MOLAR_MASS *
                Math.pow(2.0 / (KAPPA + 1), exponent));

        return areaFactor * pressureFactor * kappaFactor;
    }

    // 计算相对扩散系数 Dm
    public static double calculateDiffusionCoefficient() {
        return D0 * EPSILON_XI;  // Dm = D0 * ε*ξ
    }

    // 计算浓度场分布 C(r,t) - 主要公式2
    public static double calculateConcentration(double r, double t,
                                                double qm, double Dm, double R0) {
        if (r <= 0 || t <= 0) {
            return 0.0;
        }

        // 公式: C(r,t) = [qm / (4πDm r)] * {1 - erf[(r - R0) / (2√(Dm t))]}

        // 第一部分: qm / (4πDm r)
        double part1 = qm / (4 * Math.PI * Dm * r);

        // 第二部分: (r - R0) / (2√(Dm t))
        double argument = (r) / (2 * Math.sqrt(Dm * t));

        // 误差函数计算
        double errorFunction = erf(argument);

        // 最终浓度 (转换为 %vol)
        double concentration = part1 * (1 - errorFunction) * 100;

        return Math.max(0, concentration); // 确保非负
    }

    // 执行完整计算
    public static CalculationResult performCalculation(InputParameters params) {
        CalculationResult result = new CalculationResult();

        // 1. 计算泄漏质量流量
        result.massFlowRate = calculateMassFlowRate(params);

        // 2. 计算扩散系数
        result.diffusionCoefficient = calculateDiffusionCoefficient();

        // 3. 计算浓度分布
        result.concentrationDistribution = new TreeMap<>();

        double maxDistance = 20.0; // 最大计算距离
        double step = 0.1;          // 计算步长
        double stopConcentration = 1.0; // 停止浓度 1%vol

        for (double r = step; r <= maxDistance; r += step) {
            double concentration = calculateConcentration(
                    r, params.time, result.massFlowRate,
                    result.diffusionCoefficient, params.r0
            );

            String rStr = String.format("%.2f", r);
            result.massFlowRate = Double.valueOf(String.format("%.2f",result.massFlowRate));
            String concentrationStr = String.format("%.2f", concentration);
            r = Double.valueOf(rStr);
            concentration = Double.valueOf(concentrationStr);

            result.concentrationDistribution.put(r, concentration);

            // 当浓度降到1%vol以下时停止计算
            if (concentration <= stopConcentration) {
                result.maxConcentrationDistance = r;
                break;
            }
        }

        return result;
    }

    // 验证泄漏口形状输入是否有效
    public static boolean isValidLeakShape(String shape) {
        String lowerShape = shape.toLowerCase();
        return lowerShape.equals("circle") ||
                lowerShape.equals("triangle") ||
                lowerShape.equals("rectangle");
    }

    // 获取所有支持的泄漏口形状
    public static List<String> getSupportedLeakShapes() {
        return Arrays.asList("Circle", "Triangle", "Rectangle");
    }

    // 生成浓度渐变图数据
    public static void generateConcentrationGradient(CalculationResult result, InputParameters params) {
        System.out.println("Underground Gas Diffusion Analysis Model");
        System.out.println("========================================");
        System.out.printf("Leak Shape: %s\n", params.leakShape);
        System.out.printf("Flow Coefficient (α): %.2f\n", getFlowCoefficient(params.leakShape));
        System.out.printf("Mass Flow Rate: %.6f kg/s\n", result.massFlowRate);
        System.out.printf("Diffusion Coefficient: %.6f m²/s\n", result.diffusionCoefficient);
        System.out.println("Concentration Distribution (Distance vs Concentration %vol):");
        System.out.println("Distance(m)\tConcentration(%vol)");

        int count = 0;
        for (Map.Entry<Double, Double> entry : result.concentrationDistribution.entrySet()) {
            //if (count % 10 == 0) { // 每10个点输出一次，避免输出过多
                System.out.printf("%.2f\t\t%.6f\n", entry.getKey(), entry.getValue());
            //}
            //count++;

            // 当浓度接近1%时输出更多点
            if (entry.getValue() <= 1.1 && entry.getValue() >= 0.9) {
                System.out.printf("%.2f\t\t%.6f\n", entry.getKey(), entry.getValue());
            }
        }

        System.out.printf("Maximum distance reaching 1%%vol concentration: %.2f m\n", result.maxConcentrationDistance);
    }

/*
    // 生成HTML渐变图（控制台模拟）
    public static void generateHTMLGradient(CalculationResult result) {
        System.out.println("\nConcentration Gradient (Console Simulation):");
        System.out.println("High ███ Medium ▓▓▓ Low ░░░");

        Map<Double, Double> dist = result.concentrationDistribution;
        List<Double> distances = new ArrayList<>(dist.keySet());
        Collections.sort(distances);

        for (int i = 0; i < Math.min(20, distances.size()); i += 2) {
            double r = distances.get(i);
            double c = dist.get(r);

            String block;
            if (c > 10) block = "███";
            else if (c > 5) block = "▓▓▓";
            else if (c > 1) block = "░░░";
            else block = "   ";

            System.out.printf("Distance %.1fm: %s (%.2f%%vol)\n", r, block, c);
        }
    }
*/

    @ApiOperation("浓度场分布")
    @PostMapping("/concentrationDistribution")
    public AjaxResult concentrationDistribution(@RequestBody GasDiffusionModelDto gasDiffusionModelDto) {
        AjaxResult ajaxResult = new AjaxResult();
        Map map = new HashMap();
        map.put("number" , gasDiffusionModelDto.getNumber());
        map.put("input" , gasDiffusionModelDto);

        // 创建输入参数
        InputParameters params = new InputParameters();
        params.pressure = 200000;      // 200000 Pa
        params.temperature = 285;       // 285 K
        params.leakShape = "circle";    // 泄漏口形状
        params.leakDiameter = 0.01;    // 0.01 m
        //params.R0 = 1.0;               // 1.0 m
        params.time = 3600;            // 3600秒 (1小时)

        if(null == gasDiffusionModelDto)
        {
            return ajaxResult.success("请检查输入的参数是否正确！");
        }
        if(gasDiffusionModelDto.getPressure() > 0)
        {
            params.pressure = gasDiffusionModelDto.getPressure();
        }

        if(gasDiffusionModelDto.getTemperature() > 0)
        {
            params.temperature = gasDiffusionModelDto.getTemperature();
        }
        if(null != gasDiffusionModelDto.getLeakShape() && isValidLeakShape(gasDiffusionModelDto.getLeakShape()))
        {
            params.leakShape = gasDiffusionModelDto.getLeakShape();
        }
        else
        {
            params.leakShape = "circle";    // 用默认的
        }

        if(gasDiffusionModelDto.getLeakDiameter() > 0)
        {
            params.leakDiameter = gasDiffusionModelDto.getLeakDiameter();
        }

        if(gasDiffusionModelDto.getTime() > 0)
        {
            params.time = gasDiffusionModelDto.getTime();
        }

        Double totalTime = params.time;

        List<CalculationResult> calculationResultList = new ArrayList<>();
        for(int i=0;i < totalTime/600;i++)
        {
            params.time = (i+1)  * 600;
            // 执行计算
            CalculationResult result = performCalculation(params);

            // 输出结果
            generateConcentrationGradient(result, params);
            result.leakTime = params.time;
            calculationResultList.add(result);
        }
        map.put("result",calculationResultList);
        return ajaxResult.success(map);
    }

        public static void main(String[] args) {
        // 创建输入参数
        InputParameters params = new InputParameters();
        params.pressure = 200000;      // 200000 Pa
        params.temperature = 285;       // 285 K
        params.leakShape = "Circle";    // 泄漏口形状 (改为英文)
        params.leakDiameter = 0.01;    // 0.01 m
        //params.R0 = 1.0;               // 1.0 m
        params.time = 3600;            // 3600秒 (1小时)

        // 验证泄漏口形状
        if (!isValidLeakShape(params.leakShape)) {
            System.out.println("Warning: Invalid leak shape. Using default: Circle");
            params.leakShape = "Circle";
        }

        // 执行计算
        CalculationResult result = performCalculation(params);

        // 输出结果
        generateConcentrationGradient(result, params);
        //generateHTMLGradient(result);

        // 测试不同泄漏口形状
        System.out.println("\n不同泄漏口形状的比较:");
        System.out.println("Shape\t\tMass Flow Rate (kg/s)");

        for (String shape : getSupportedLeakShapes()) {
            params.leakShape = shape;
            CalculationResult shapeResult = performCalculation(params);
            System.out.printf("%s\t\t%.6f\n", shape, shapeResult.massFlowRate);
        }

        // 测试不同时间点
        System.out.println("\n不同时间点的扩散范围:");
        System.out.println("Time(hours)\tMax Diffusion Distance(m)");

        double[] timePoints = {1, 2, 4, 8, 12, 24}; // 小时
        for (double hours : timePoints) {
            params.time = hours * 3600; // 转换为秒
            CalculationResult timeResult = performCalculation(params);
            System.out.printf("%.0f\t\t%.2f\n", hours, timeResult.maxConcentrationDistance);
        }
    }
}
